package cn.tedu.zblogs.home.utils;


import cn.tedu.zblogs.home.config.ESConfig;
import cn.tedu.zblogs.home.pojo.VO.ArticleEsVO;
import com.alibaba.fastjson.JSON;
import java.util.ArrayList;

import lombok.extern.slf4j.Slf4j;
import com.alibaba.fastjson.JSONObject;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;

import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.IndicesClient;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;

import org.elasticsearch.search.SearchHits;
import org.springframework.stereotype.Component;

import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * Es工具类
 */
@Slf4j
@Component
public class EsUtil {
    private RestHighLevelClient restHighLevelClient;

    public EsUtil() {
        this.restHighLevelClient = ESConfig.getClient();
    }



    /**
     * 添加索引
     *
     * @param indexName
     * @return
     * @throws IOException
     */
    public boolean addIndex(String indexName) {



        Assert.hasLength(indexName, "Elasticsearch exception indexName null");
        CreateIndexResponse createIndexResponse = null;
        try {
            //1.使用client获取操作索引对象
            IndicesClient indices = restHighLevelClient.indices();
            //2.具体操作获取返回值
            //2.1 设置索引名称
            CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
            // String mappings = "{ \"settings\": { \"analysis\": { \"analyzer\": { \"ik_analyzer\": { \"type\": \"ik_smart\" } } } }, \"mappings\": { \"properties\": { \"content\": { \"type\": \"text\", \"analyzer\": \"ik_analyzer\" } } } } }";
            // createIndexRequest.mapping(mappings, XContentType.JSON);


            createIndexResponse = indices.create(createIndexRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
//            e.printStackTrace();
            log.error("elasticsearch addindex error , meassage = {}", e.getMessage());
            //打印轨迹
            log.error(e.getMessage(), e);
            //throw new BusinessException("elasticsearch addindex error , meassage=" + e.getMessage());
        }

        //3.根据返回值判断结果
        return createIndexResponse.isAcknowledged();
    }


    /**
     * 创建数据
     *
     * @param indexName
     * @param id
     * @param data
     * @throws IOException
     */
    public boolean addData(String indexName, String id, Object data) {
        Assert.notNull(data, "Elasticsearch exception data null");
        Assert.hasLength(indexName, "Elasticsearch exception indexName null");
        IndexResponse indexResponse = null;
        try {
            //准备文档
            String jsonString = JSONObject.toJSONString(data);
            Map jsonMap = JSONObject.parseObject(jsonString, Map.class);
            //创建请求 指定操作表和操作id
            IndexRequest indexRequest = new IndexRequest(indexName).id(id);
            //指定文档内容
            indexRequest.source(jsonMap);
            //true 当存在相同的_id时，插入会出现异常； false 当存在相同_id时，插入会进行覆盖；
            indexRequest.create(false);
            //通过client进行http请求
            indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("elasticsearch addOrUpdateDoc error , meassage = {}", e.getMessage());
            //打印轨迹
            log.error(e.getMessage(), e);
            //throw new BusinessException("elasticsearch addOrUpdateDoc error , meassage=" + e.getMessage());
        }
        return indexResponse.getResult().equals(DocWriteResponse.Result.CREATED);
    }


    public  List<ArticleEsVO>  MatchAllEsData(String indexName ,Integer page,Integer pageSize,String queryString){
        try {
            // 创建检索请求
            SearchRequest searchRequest = new SearchRequest(indexName);

            //组织sql参数
            //searchRequest.source().query(QueryBuilders.matchAllQuery());
            //分词查询
              searchRequest.source()
                      .query(QueryBuilders.matchQuery("all", queryString));
            // 2.2.排序 sort
            searchRequest.source().sort("id", SortOrder.DESC);
            // 2.3.分页 from、size
            searchRequest.source().from((page - 1) * pageSize).size(pageSize);


            //可以使用高亮显示，就是html标签
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.preTags("<span class='highlighted'>")
                    .postTags("</span>")
                    .field("title").requireFieldMatch(false);


            highlightBuilder.preTags("<span class='highlighted'>")
                    .postTags("</span>")
                    .field("content").requireFieldMatch(false);
            // 2.2.高亮对象写入查询对象
            searchRequest.source().highlighter(highlightBuilder);

//            //可以使用高亮显示，就是html标签
//            HighlightBuilder highlightBuilder2 = new HighlightBuilder();
//            highlightBuilder2.preTags("<span class='highlighted'>")
//                    .postTags("</span>")
//                    .field("content").requireFieldMatch(false);
//            // 2.2.高亮
//            searchRequest.source().highlighter(highlightBuilder2);



            //发送请求
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            //4解析结果
            List<ArticleEsVO> list =handleResponse(searchResponse);
            return  list;

        } catch (Exception e) {
            log.error("elasticsearch selectDataList error , meassage = {}", e.getMessage());
            //打印轨迹
            log.error(e.getMessage(), e);
            List<ArticleEsVO> list = new ArrayList<>();
            return  list;
            // throw new BusinessException("elasticsearch selectDataList error , meassage=" + e.getMessage());
        }
    }


    private List<ArticleEsVO> handleResponse(SearchResponse response) {
// 4.解析响应
        SearchHits searchHits = response.getHits();
// 4.1.获取总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("共搜索到" + total + "条数据");
// 4.2.文档数组
        SearchHit[] hits = searchHits.getHits();
// 4.3.遍历
        List<ArticleEsVO> list = new ArrayList<>();
        for (SearchHit hit : hits) {
// 获取文档source
            String json = hit.getSourceAsString();
// 反序列化
            ArticleEsVO hotelDoc = JSON.parseObject(json, ArticleEsVO.class);
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (!CollectionUtils.isEmpty(highlightFields)) {
                // 根据字段名获取高亮结果
                HighlightField highlightField = highlightFields.get("title");
                if (highlightField != null) {
                    // 获取高亮值
                    String name = highlightField.getFragments()[0].string();
                    // 覆盖非高亮结果
                    hotelDoc.setTitle(name);
                }
                // 根据字段名获取高亮结果
                HighlightField highlightField2 = highlightFields.get("content");
                if (highlightField2 != null) {
                    // 获取高亮值
                    String content = highlightField2.getFragments()[0].string();
                    // 覆盖非高亮结果
                    hotelDoc.setContent(content);
                }
            }


            list.add(hotelDoc);
            System.out.println("hotelDoc = " + hotelDoc);
        }
        return  list;
    }




    /**
     * 删除索引
     *
     * @param indexName
     * @return
     * @throws IOException
     */
    public boolean deleteIndex(String indexName) {
        Assert.hasLength(indexName, "Elasticsearch exception indexName null");
        AcknowledgedResponse deleteRespone = null;
        try {
            //1.使用client获取操作索引对象
            IndicesClient indices = restHighLevelClient.indices();
            //2.具体操作获取返回值
            //2.1 设置索引名称
            DeleteIndexRequest request = new DeleteIndexRequest("twitter_two");//指定要删除的索引名称
            deleteRespone = indices.delete(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
//            e.printStackTrace();
            log.error("elasticsearch deleteIndex error , meassage = {}", e.getMessage());
            //打印轨迹
            log.error(e.getMessage(), e);
          //  throw new BusinessException("elasticsearch deleteIndex error , meassage=" + e.getMessage());
        }
        //3.根据返回值判断结果
        return deleteRespone.isAcknowledged();
    }



}
